5.5. 构建处理器:将所有内容整合在一起
中央处理单元(CPU)实现了冯·诺依曼体系结构的处理和控制单元,这些部分驱动程序指令对程序数据的执行(参见图 1)。
图 1. CPU 实现了冯·诺依曼架构的处理和控制单元部分。
CPU 由基本的算术/逻辑、存储和控制电路构建模块构成,其主要功能部件包括:执行算术和逻辑运算的算术逻辑单元(ALU);一组用于存储程序数据的通用寄存器;一些用于实现指令执行的控制电路和专用寄存器;以及驱动 CPU 电路执行程序指令的时钟。
本节介绍 CPU 的主要部件,包括 ALU 和寄存器文件,并说明如何将它们组合起来实现 CPU。下一节将讨论 CPU 如何执行程序指令以及如何使用时钟来驱动程序指令的执行。
5.5.1. ALU
ALU 是一个复杂的电路,可实现有符号和无符号整数的所有算术和逻辑运算。单独的浮点单元对浮点值执行算术运算。ALU 采用整数操作数值和 opcode 值,该值指定要执行的操作(例如加法)。ALU 输出对操作数输入执行指定操作的结果值和 条件码 值,该值对操作结果的信息进行编码。常见的条件码指定 ALU 结果是负数、零还是操作中是否有进位位。例如,给定 C 语句
x = 6 + 8;
CPU 通过将操作数值(6 和 8)和编码 ADD 运算的位馈送到 ALU 电路来开始执行加法。ALU 计算结果并将其与条件代码一起输出,以指示结果为非负、非零且不会导致进位。每个条件代码都编码在一个位中。位值为 1 表示条件成立,位值为 0 表示它不适用于 ALU 结果。在我们的示例中,位模式 000 指定与执行 6+8 相关的三个条件集:结果不为负(0)、不为零(0)并且进位值为零(0)。
条件代码由 ALU 在执行操作时设置,有时会被后续指令使用,这些指令会根据特定条件选择操作。例如,ADD 指令可以计算以下if
语句的 (x + 8) 部分:
if( (x + 8) != 0 ) {
x++;
}
ALU 执行 ADD 指令时会根据(x + 8)
相加的结果设置条件码。在 ADD 指令之后执行的条件跳转指令会测试 ADD 指令设置的条件码位,并根据其值进行跳转(跳过执行if
主体中的指令)或不跳转。例如,如果 ADD 指令将零条件码设置为 0,则条件跳转指令将不会跳转与if
主体相关的指令(零条件码为 0 表示 ADD 的结果不为零)。如果零条件码为 1,它将跳转跳过if
主体指令。为了实现跳过一组指令,CPU 将if
主体指令后的第一条指令的内存地址写入程序计数器(PC),其中包含下一条要执行的指令的地址。
ALU 电路将多个算术和逻辑电路(用于实现其一组操作)与多路复用器电路相结合,以选择 ALU 的输出。简单的 ALU 不会尝试选择性地仅激活与特定操作相关的算术电路,而是将其操作数输入值发送到其所有内部算术和逻辑电路。ALU 的所有内部算术和逻辑电路的输出都输入到其多路复用器电路,该电路选择 ALU 的输出。ALU 的操作码输入用作多路复用器的信号输入,以选择将哪个算术/逻辑操作选为 ALU 的输出。条件代码输出基于 MUX 输出,并结合电路来测试输出的值以确定每个条件代码位。
图 2 显示了一个示例 ALU 电路,该电路对两个 32 位操作数执行四种不同的运算(ADD、OR、AND 和 EQUALS)。它还会产生一个条件码输出,指示运算结果是否为零。请注意,ALU 将操作码定向到多路复用器,该多路复用器选择输出 ALU 的四个算术结果中的哪一个。
图 2. 四操作 ALU,对两个 32 位操作数执行 ADD、OR、AND 和 EQUALS 运算。它有一个条件代码输出位,用于指定结果是否为 0。
ALU 的操作码输入来自 CPU 正在执行的指令中的位。例如,ADD 指令的二进制编码可能由四部分组成:
| OPCODE BITS | OPERAND A SOURCE | OPERAND B SOURCE | RESULT DESTINATION |
根据 CPU 架构,操作数源位可能编码 CPU 寄存器、存储操作数值的内存地址或文字操作数值。例如,在执行 6 + 8 的指令中,文字值 6 和 8 可以直接编码到指令的操作数说明符位中。
对于我们的 ALU,操作码需要两位,因为 ALU 支持四种操作,两位可以编码四个不同的值 (00、01、10、11),每个操作一个值。通常,执行 N 个不同操作的 ALU 需要 log2(N) 个操作码位来指定从 ALU 输出哪个操作结果。
图 3 展示了如何将 ADD 指令的操作码和操作数位用作 ALU 的输入。
图 3. ALU 使用指令中的操作码位来选择输出哪个操作。在此示例中,ADD 指令中的不同位被输入到 ALU 操作数和操作码输入中,以执行 6 和 8 的加法。
5.5.2. 寄存器文件
在内存层次结构的顶部,CPU 的通用寄存器组存储临时值。CPU 提供的寄存器数量非常少,通常为 8-32 个(例如,IA32 架构提供 8 个,MIPS 提供 16 个,ARM 提供 13 个)。指令通常从通用寄存器获取操作数值或将结果存储到通用寄存器。例如,ADD 指令可以编码为“将寄存器 1 中的值添加到寄存器 2 中的值,并将结果存储在寄存器 3 中”。
CPU 的通用寄存器集被组织成一个 寄存器文件 电路。寄存器文件由一组 寄存器电路 用于存储数据值和一些 控制电路 用于控制对其寄存器的读写组成。该电路通常具有一条数据输入线,用于将值写入其一个寄存器,以及两条数据输出线,用于同时从其寄存器读取两个值。
图 4 显示了具有四个寄存器的寄存器文件电路的示例。 它的两个输出值(Data out0 和 Data out1)由两个多路复用器电路控制。 它的每个读取选择输入(Sr0 和 Sr1)都被馈送到其中一个 MUX,以选择相应输出的寄存器值。 寄存器文件的数据输入(Data in line)被发送到每个寄存器电路,它的写使能(WE)输入首先通过解复用器(DMUX)电路,然后再发送到每个寄存器电路。 DMUX 电路接受一个输入值并选择将该值发送到 N 个输出中的哪一个,将剩余的 N-1 个输出发送 0。 寄存器文件的写选择输入(Sw)被发送到 DMUX 电路以选择 WE 值的目标寄存器。当寄存器文件的 WE 输入值为 0 时,不会将任何值写入寄存器,因为每个寄存器的 WE 位也为 0(因此,Data in 对存储在寄存器中的值没有影响)。当 WE 位为 1 时,DMUX 仅向写选择输入 (Sw) 指定的寄存器输出 WE 位值 1,从而导致 Data in 值仅写入选定的寄存器。
图 4. 寄存器文件:用于存储指令操作数和结果值的一组 CPU 通用寄存器。
特殊用途寄存器
除了寄存器文件中的一组通用寄存器之外,CPU 还包含专用寄存器,用于存储指令的地址和内容。程序计数器 (PC) 存储下一条要执行的指令的内存地址,指令寄存器 (IR) 存储 CPU 正在执行的当前指令的位。存储在 IR 中的指令位在指令执行期间用作 CPU 不同部分的输入。我们将在下一节指令执行 中更详细地讨论这些寄存器。
5.5.3. CPU
利用 ALU 和寄存器文件电路,我们可以构建 CPU 的主要部分,如 图 5 所示。由于指令操作数通常来自存储在通用寄存器中的值,因此寄存器文件的输出会将数据发送到 ALU 的输入。同样,由于指令结果通常存储在寄存器中,因此 ALU 的结果输出会作为输入发送到寄存器文件。CPU 具有额外的电路来在 ALU、寄存器文件和其他组件(例如主存储器)之间移动数据。
图 5. ALU 和寄存器文件构成了 CPU 的主要部分。ALU 执行操作,寄存器文件存储操作数和结果值。其他专用寄存器存储指令地址 (PC) 和内容 (IR)。请注意,指令可能会从寄存器文件以外的位置(例如主存储器)检索操作数或将结果存储到其他位置。
CPU 的这些主要部分构成了它的数据路径。数据路径由执行算术和逻辑运算(ALU)和存储数据(寄存器)的 CPU 部分以及连接这些部分的总线组成。CPU 还实现了一条控制路径,该路径驱动 ALU 对存储在寄存器文件中的操作数执行程序指令。此外,控制路径向 I/O 设备发出命令并根据指令的需要协调内存访问。例如,某些指令可能直接从内存位置而不是通用寄存器获取其操作数值(或将其结果直接存储到内存位置)。在下一节中,我们将重点讨论获取操作数值并将结果存储到寄存器文件的指令上的 CPU 指令执行。CPU 需要额外的控制电路来读取操作数值或将指令结果写入其他位置,但无论源位置和目标位置如何,主要指令执行步骤的行为都相同。